Skip to content

feat(audio): mute system output while recording#101

Open
ccharname wants to merge 2 commits into
missuo:mainfrom
ccharname:feat/mute-system-output
Open

feat(audio): mute system output while recording#101
ccharname wants to merge 2 commits into
missuo:mainfrom
ccharname:feat/mute-system-output

Conversation

@ccharname

Copy link
Copy Markdown

What

Mutes other apps' audio output for the duration of a recording, so background playback neither distracts the speaker nor bleeds into the microphone.

How

SPAudioCaptureManager mutes the current default output device on capture start and restores exactly that device on stop (remembered explicitly, so a mid-session default-route change can't leave the wrong device muted). If the device was already muted by the user, it is left untouched and the restore is skipped. Devices without a master-mute property are detected and skipped gracefully. Implemented purely via CoreAudio (kAudioDevicePropertyMute), no new dependencies.

Testing

  • make/Xcode Release build passes.
  • Verified both trigger modes (hold-to-talk and tap-to-toggle) — muting/restoring is tied to capture start/stop, so it is independent of the trigger mode.
  • Verified restore on normal stop, on an already-user-muted device (no-op + no erroneous unmute), and across a default-output change during recording.

Notes

  • CHANGELOG.md updated under an Unreleased section.
  • docs/update-feed.json left untouched — it tracks published releases (currently still at 1.0.14) and is best updated by the maintainer at release time.

zheng added 2 commits May 30, 2026 11:33
Silence other apps' playback for the duration of a recording so it neither
distracts the speaker nor bleeds into the mic. Mutes the current default
output device on capture start and restores exactly that device on stop;
leaves an already-user-muted device untouched (and skips the restore).
@missuo

missuo commented May 30, 2026

Copy link
Copy Markdown
Owner

Thanks for the PR — the implementation is clean and well thought through: pure CoreAudio with no new deps, remembering the exact device so a mid-session default-route change can't strand the wrong one, skipping devices the user had already muted, and gracefully handling devices without a master-mute property. Nice work.

I'd like one design change before merging, plus one robustness fix.

1. Make it an opt-in setting (default off), not automatic

I'd prefer muting to be a user choice rather than always-on. kAudioDevicePropertyMute toggles the mute of the entire output device system-wide (the same mute as the keyboard mute key / the menu-bar volume), so for a menu-bar dictation tool that records on every hotkey press, silencing all system audio every time is surprising for anyone who dictates while listening to music, a meeting, or a video. This is also how comparable tools (e.g. Typeless) handle it — you can choose to mute playback or leave it alone.

Concretely, this can follow the existing feedback.start_sound path end to end:

  • add a bool field in koe-core/src/config.rs (mirror FeedbackSection);
  • read it at runtime like sp_core_get_feedback_config() (or via the generic configGet);
  • add an NSSwitch in the General pane of SPSetupWizardWindowController (next to the Trigger / Feedback Sounds cards), wired into saveConfig: and the load path via configSet/configGet;
  • gate the [self muteSystemOutput] call in SPAudioCaptureManager behind the flag — e.g. a muteOutputEnabled property that SPAppDelegate sets before startCapture, the same way pendingDeviceID is injected.

The default should be off, so existing users' behavior is unchanged and the people who want it can turn it on.

2. Restore on abnormal exit

restoreSystemOutput only runs from stopCapture. If the app crashes, is force-quit, or is killed while recording, the device stays muted — and because device mute is a persistent system property, the user is left with silent output and no obvious cause, even after relaunching the app. Please also restore on applicationWillTerminate: to cover a normal quit while recording. SIGKILL can't be caught, which is also a reason to reconsider whether a global device-level mute is the right hammer here versus a lighter approach — happy to discuss.

Minor

  • Once it's a setting, please reword the CHANGELOG entry (it currently says "automatic muting…"), e.g. "optional setting to mute system audio while recording (off by default)".

Everything else looks solid: the mute/restore pairing is balanced and idempotent across the various stopCapture call sites, and remembering the muted device (instead of re-reading the default output at stop) correctly handles a mid-recording output change. Thanks again — looking forward to the updated version!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants